# Introducción al uso de bases de datos con R

### Clase 2 - rbase y tidyverse para el manejo de bases de datos

#### 25/10/2019

# Estructuración de Bases de Datos

A lo largo de esta clase veremos como trabajar con bases de datos.

Para mostrar las principales funciones que usaremos, crearemos un pequeño set de datos, con datos de hogares.

    HOGAR  <- c(1,1,1,1,2,3,3)
    MIEMBRO  <- c(1,2,3,4,1,1,2)
    SEXO  <-  c("Varon","Mujer","Mujer","Varon","Mujer","Varon","Mujer")
    EDAD  <-  c(60,54,18,27,32,71,66)
    NIVEL_ED  <-  c("Secundario","Terciario","Secundario","Secundario","Universitario",NA,"Primario")
    ESTADO  <-  c("Ocupado","Ocupado","Inactivo","Desocupado","Ocupado","Inactivo","Inactivo")

    Datos <- data.frame(HOGAR,MIEMBRO, SEXO, EDAD, NIVEL_ED, ESTADO)

## R base

Para empezar, mostraremos algunos comandos básicos que nos permiten conocer la estructura de nuestra base.

### str

Para tener una vista preliminar y conocer la estructura básica de nuestros datos, podemos usar la función str. La misma nos indica la cantidad de observaciones y de variables de nuestra base, y para cada variable nos indica el tipo de variable y nos muestra las primeras observaciones:

    str(Datos)

    'data.frame':   7 obs. of  6 variables:
     $ HOGAR   : num  1 1 1 1 2 3 3
     $ MIEMBRO : num  1 2 3 4 1 1 2
     $ SEXO    : Factor w/ 2 levels "Mujer","Varon": 2 1 1 2 1 2 1
     $ EDAD    : num  60 54 18 27 32 71 66
     $ NIVEL_ED: Factor w/ 4 levels "Primario","Secundario",..: 2 3 2 2 4 NA 1
     $ ESTADO  : Factor w/ 3 levels "Desocupado","Inactivo",..: 3 3 2 1 3 2 2

### summary

Nos sirve para conocer los estadísticos principales de las variables:

    summary(Datos)

         HOGAR          MIEMBRO       SEXO        EDAD                NIVEL_ED        ESTADO
     Min.   :1.000   Min.   :1.0   Mujer:4   Min.   :18.00   Primario     :1   Desocupado:1
     1st Qu.:1.000   1st Qu.:1.0   Varon:3   1st Qu.:29.50   Secundario   :3   Inactivo  :3
     Median :1.000   Median :2.0             Median :54.00   Terciario    :1   Ocupado   :3
     Mean   :1.714   Mean   :2.0             Mean   :46.86   Universitario:1
     3rd Qu.:2.500   3rd Qu.:2.5             3rd Qu.:63.00   NA's         :1
     Max.   :3.000   Max.   :4.0             Max.   :71.00

### names

Si quisiéramos conocer los nombres de las variables de nuestro dataframe, podríamos usar la función names:

    names(Datos)

    [1] "HOGAR"    "MIEMBRO"  "SEXO"     "EDAD"     "NIVEL_ED" "ESTADO"

### table

Otra función muy útil es table, que nos da la frecuencia de una variable.

    table(Datos$NIVEL_ED)

         Primario    Secundario     Terciario Universitario
                1             3             1             1

### is.na

En R los valores perdidos (missing values o “NA” - not available-) condicionan la manera en que se trabaja con el programa. Entonces, resulta muy importante conocer su existencia, dónde se encuentran y cuántos son, ya que tienen que ser tratados de manera particular y muchas veces influyen en la escritura de funciones.

Para conocer si hay missing values y cuáles son las variables que los contienen, podemos hacerlo ejecutando el siguiente comando:

    is.na(Datos)

         HOGAR MIEMBRO  SEXO  EDAD NIVEL_ED ESTADO
    [1,] FALSE   FALSE FALSE FALSE    FALSE  FALSE
    [2,] FALSE   FALSE FALSE FALSE    FALSE  FALSE
    [3,] FALSE   FALSE FALSE FALSE    FALSE  FALSE
    [4,] FALSE   FALSE FALSE FALSE    FALSE  FALSE
    [5,] FALSE   FALSE FALSE FALSE    FALSE  FALSE
    [6,] FALSE   FALSE FALSE FALSE     TRUE  FALSE
    [7,] FALSE   FALSE FALSE FALSE    FALSE  FALSE

También podemos hacerlo para una variable específica de nuestro dataframe:

    is.na(Datos$HOGAR)

    [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE

Como observamos en el comando anterior table, la tabla nos brinda la frecuencia de la variable NIVEL_ED para todas las categorías válidas de esa variable. Sin embargo, no nos muerta el valor perdido que nosotros vimos previamente que dicha variable contenía.

Para que la tabla nos muestre también la frecuencia de los valores perdidos es necesario especificarlo.

    table(Datos$NIVEL_ED, exclude = NULL)

         Primario    Secundario     Terciario Universitario          <NA>
                1             3             1             1             1

Supongamos ahora que la variable EDAD tiene un missing value:

    Datos$EDAD[2] <- NA
    Datos$EDAD

    [1] 60 NA 18 27 32 71 66

Que sucedería si queremos calcular el promedio de edad?

    mean(Datos$EDAD)

    [1] NA

El resultado que obtenemos es nulo. Entonces, para poder calcular el promedio de una variable que tiene datos perdidos, considerando únicamente todos los valores válidos, tenemos que agregar na.rm = TRUE

    mean(Datos$EDAD, na.rm = TRUE)

    [1] 45.66667

Lo mismo nos sucedería con otras funciones que hacen operaciones sobre variables numéricas con valores perdidos, por ejemplo:

    sum(Datos$EDAD)

    [1] NA

    sum(Datos$EDAD, na.rm = TRUE)

    [1] 274

Pero no si simplemente queremos contar la cantidad de elementos de un vector:

    length(Datos$EDAD)

    [1] 7

Volvemos a corregir el dato y lo dejamos como estaba originalmente:

    Datos$EDAD[2] <- 54
    Datos$EDAD

    [1] 60 54 18 27 32 71 66

## Librería tidyverse

Ahora introduciremos la librería Tidyverse, que agrupa una serie de paquetes que tienen una misma lógica en su diseño y, por ende, funcionan en armonía.
Entre ellos usaremos principalmente dplyr y tidyr para realizar transformaciones sobre nuestro set de datos.

A continuación cargamos la librería a nuestro ambiente. Para ello debe estar previamente instalada en nuestra pc.

    #install.packages("tidyverse")
    library(tidyverse)

### Dplyr

Este paquete sirve para poder transformar bases de datos de forma eficiente, sencilla y bastante intuitiva.

Vamos a ir viendo distintas funciones útiles que se encuentran comprendidas en esta librería.

Todas las funciones tienen en común la utilización de un caracter: `%>%` , pipe (de tubería), que es el que nos va a permitir unir los distintos comandos que queramos ejecutar.

Los `%>%` toman el set de datos a su izquierda, y los transforman mediante los comandos a su derecha, en los cuales los elementos de la izquierda están implícitos. Es decír, que una vez específicado el DataFrame con el cual se trabaja, no será necesario nombrarlo nuevamente para referirse a una determinada variable/columna del mismo.

Veamos las principales funciones que pueden utilizarse con la lógica de este paquete:

### filter

Permite filtrar observaciones de una base de datos acorde al cumplimiento de condiciones lógicas

    filter(Datos,EDAD>40 & ESTADO == "Ocupado")

    # O, lo que es lo mismo:
    # Datos %>%
    #   filter(EDAD>40 , ESTADO == "Ocupado")

Nótese que en este caso al separar con una `,` las condiciones se exige el cumplimiento de ambas (sería lo mismo usar el operador &). En caso de desear que se cumpla una de ambas condiciones debe utilizarse el operador `|`, que significa “ó”.

    Datos %>%
      filter(EDAD>40 |  ESTADO == "Ocupado")

### rename

Permite renombrar una columna (variable) de la base de datos.

Funciona de la siguiente manera: `Data %>% rename( nuevo_nombre = viejo_nombre )`

    Datos %>%
      rename(NMIEMBRO = MIEMBRO)

Nótese que a diferencia del ejemplo de la función filter donde utilizábamos == para comprobar una condición lógica, en este caso se utiliza sólo un = ya que lo que estamos haciendo es asignar un nombre.

### mutate

Sirve para crear una nueva variable en la base de datos. Se debe especificar el nombre de la nueva variable seguido de el signo “=” y a continuación la definición de cómo se conforma la nueva variable. La misma puede ser el resultado de operaciones sobre otras variables de la misma tabla.

En caso de especificar el nombre de una columna existente, el resultado de la operación realizada “sobrescribirá” la información de la columna con dicho nombre.

    Datos %>%
      mutate(EDAD_ALCUADRADO=EDAD*EDAD)

### case_when

Permite definir condiciones excluyentes. Se puede utilizar en conjunto con la función “mutate” para crear una variable que tome determinados valores cuando cumple una condición. En caso de no cumplir ninguna de las condiciones establecidas la variable tomara valor NA.

Es equivalente a la función CASE WHEN de SQL.

Su funcionamiento es el siguiente:
`case_when(condicion1 ~ "Valor1",condicion2 ~ "Valor2",condicion3 ~ "Valor3")`

    Datos <- Datos %>%
      mutate(GRUPO_EDAD = case_when(EDAD < 29 ~ "Joven",
                                    EDAD >=29 & EDAD<60  ~ "Adulto",
                                    EDAD >=60  ~ "Adulto mayor"))
    Datos

### select

Permite especificar la serie de columnas que se desea conservar de un DataFrame. También pueden especificarse las columnas que se desean descartar (agregándoles un -). Muy útil para agilizar el trabajo en bases de datos de gran tamaño.

    Datos %>%
      select(HOGAR,MIEMBRO,SEXO)

     Datos %>%
      select(-c(SEXO,GRUPO_EDAD))

### arrange

Permite ordenar una tabla por los valores de determinada/s variable/s. Es útil cuando luego deben hacerse otras operaciones que requieran del ordenamiento de la tabla

    Datos %>%
      arrange(ESTADO, EDAD)

    Datos %>%
      arrange(desc(ESTADO), EDAD)

### summarise

Sirve para resumir/agrupar la información de una base de datos en una nueva tabla. Para ello, es necesario definir las variables de resumen y la función de agregación.

    Datos %>%
      summarise(Edad_prom = mean(EDAD))

### group_by

Esta función permite realizar operaciones de forma agrupada. Lo que hace la función es agrupar las observaciones (filas) según las categorías de la/s variable/s indicada en la función group_by y dentro de cada uno de esos “grupos de observaciones” de la tabla, hacer la operación especificada de manera independiente. En nuestro ejemplo, sería útil para calcular el promedio de edad por ESTADO

    Datos %>%
      group_by(ESTADO) %>%
      summarise(EDAD_PROM = mean(EDAD))

    Datos %>%
      group_by(SEXO,ESTADO) %>%
      summarise(EDAD_PROM = mean(EDAD))

Notese que los `%>%` pueden usarse encadenados para realizar numerosos procedimientos sobre un dataframe original.

Veamos un ejemplo con multiples encadenamietnos

    Datos %>%
      filter(HOGAR == 1) %>%
      rename(NMIEMBRO = MIEMBRO) %>%
      mutate(GRUPO_EDAD = case_when(EDAD < 29 ~ "Joven",
                                    EDAD >=29 & EDAD<60  ~ "Adulto",
                                    EDAD >=60  ~ "Adulto mayor"))%>%
      select(-NIVEL_ED)

    NA

## Joins

Otra implementación muy importante del paquete dplyr son las funciones para unir diferentes tablas (joins)

fuente: http://rstudio-pubs-static.s3.amazonaws.com/227171_618ebdce0b9d44f3af65700e833593db.html

### left_join

Veamos un ejemplo de la función left_join (una de las más utilizadas en la práctica).
Para ello crearemos previamente otro Dataframe que contenga un Ponderador para cada hogar del Dataframe Datos.

    Ponderadores <- data.frame(HOGAR = c(1,2,3),
                               PONDERADOR = c(264,520,310))
    Ponderadores

Ahora que tenemos las dos tablas, vamos a unirlas de manera que para cada observación de la tabla “Datos”, tengamos el ponderador del hogar correspondiente.

    Datos_join <- Datos %>%
      left_join(.,Ponderadores, by = "HOGAR")
    Datos_join

Ahora, aprovecharemos el ejemplo para introducir la función weigthed.mean, y así calcular un valor ponderado, en nuestro caso, la edad promedio ponderada.

    Edad_prom_ponderada <- Datos_join %>%
      summarise(Edad_prom = weighted.mean(EDAD,w = PONDERADOR))
    Edad_prom_ponderada

## Tidyr

El paquete tidyr esta pensado para facilitar la visualización de los datos ordenandolos de la manera más conveniente.

Gather es una función que nos permite pasar los datos de forma horizontal a una forma vertical.

spread es una función que nos permite pasar los datos de forma vertical a una forma horizontal.

fuente: http://www.gis-blog.com/data-management-with-r-tidyr-part-1/

Usaremos un recorte de la base para mostrar como operan estas funciones:

    datos_recorte <- Datos %>%
      group_by(ESTADO,SEXO) %>%
      summarise(EDAD_PROM = mean(EDAD))
    datos_recorte

### Spread

    datos_spread <- datos_recorte %>%
      spread(.,          # el . llama a lo que esta atras del %>%
      key = SEXO,        #la llave es la variable cuyos valores van a dar los nombres de columnas
      value = EDAD_PROM) #los valores con que se llenan las celdas
    datos_spread

### Gather

    ##La función opuesta (gather) nos permite obtener un dataframe como el original partiendo de un dataframe como el recién construido.

    datos_gather <- datos_spread %>%
      gather(.,           # el . llama a lo que esta atras del %>%
       key   = SEXO,      # como se llamará la variable que toma los nombres de las columnas
       value = EDAD_PROM, # como se llamará la variable que toma los valores de las columnas
       2:3)               #le indico que columnas juntar
    datos_gather

[encoded data, 16436 characters]